package com.start.security.data;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.start.common.api.Result;
import com.start.common.exceptions.StartBusException;
import com.start.common.tools.SpringContextTools;
import com.start.security.configs.StartDataSecurityProperties;
import com.start.security.data.encryption.sm2.Sm2Util;
import com.start.security.service.StartSecurityService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.List;

/**
 * 网络请求返回数据加密
 */
@Slf4j
@ControllerAdvice
@ConditionalOnProperty(prefix = StartDataSecurityProperties.PREFIX, name = "enable", havingValue = "true")
public class StartResponseBodyAdvice implements ResponseBodyAdvice<Object> {
    private final StartDataSecurityProperties configuration;


    private final StartSecurityService startSecurityDataService;
    private List<String> urls;
    private final ObjectMapper objectMapper;

    public StartResponseBodyAdvice(StartSecurityService startSecurityDataService, StartDataSecurityProperties configuration, ObjectMapper objectMapper) {
        this.configuration = configuration;
        this.objectMapper = objectMapper;
        this.startSecurityDataService = startSecurityDataService;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        HttpServletRequest httpServletRequest = SpringContextTools.getHttpServletRequest();
        return startSecurityDataService.hasDataSecurity(httpServletRequest);
    }


    @Override
    public Object beforeBodyWrite(Object o, @NonNull MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest request, ServerHttpResponse serverHttpResponse) {
        if (!mediaType.equals(MediaType.APPLICATION_JSON)) {
            return o;
        }
        if (!(o instanceof Result<?> currentResult)) {
            return o;
        }
        if (currentResult.getCode() != Result.CODE_OK || currentResult.getData() == null) {
            return o;
        }
        String data;
        try {
            data = objectMapper.writeValueAsString(currentResult.getData());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new StartBusException(e);
        }
        if (StringUtils.isAllBlank(data)) {
            return o;
        }
        String encryptData = Sm2Util.encrypt(data, configuration.getServerPublicKey());
        Result<String> result = new Result<>();
        result.setData(encryptData);
        result.put(configuration.getResultEncryptKey(), true);
        return result;
    }

}
